package com.os.lambda.chapter6;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 通过手动使用县城模拟掷骰子事件
 */
public class ManualDiceRolls {

    private static final Integer N = 1000000000;

    private final double fraction;
    private final Map<Integer,Double> results;
    private final int numberOfThreads;
    private final ExecutorService executor;
    private final int workPerThread;

    public static void main(String[] args){
        ManualDiceRolls rolls = new ManualDiceRolls();
        rolls.stimulateDiceRoles();
    }

    public ManualDiceRolls(){
        fraction = 1.0/N;
        results = new ConcurrentHashMap<>();
        numberOfThreads = Runtime.getRuntime().availableProcessors();
        executor = Executors.newFixedThreadPool(numberOfThreads);
        workPerThread = N / numberOfThreads;
    }

    public void stimulateDiceRoles(){
        List<Future<?>> futures = submitJobs();
        awaitCompletion(futures);
        printResults();
    }

    private void printResults(){
        System.out.println("输出结果。。。" + results);
        results.entrySet()
                .forEach(System.out::println);
    }

    private List<Future<?>> submitJobs(){
        List<Future<?>> futures = new ArrayList<>();
        for(int i=0; i<numberOfThreads; i++){
            futures.add(executor.submit(makeJob()));
        }
        return futures;
    }

    private Runnable makeJob(){
        return ()->{
            ThreadLocalRandom random = ThreadLocalRandom.current();
            for(int i=0; i<workPerThread; i++){
                int entry = twoDiceThrows(random);
                accumulateResult(entry);
            }
        };
    }

    private void accumulateResult(int entry){
        results.compute(entry, (key, previous)->
           previous == null ? fraction : previous + fraction
        );
    }

    private int twoDiceThrows(ThreadLocalRandom random){
        int firstThrow = random.nextInt(1, 7);
        int secondThrow = random.nextInt(1, 7);
        return firstThrow + secondThrow;
    }

    private void awaitCompletion(List<Future<?>> futures){
        futures.forEach((future) -> {
            try {
                future.get();
            }catch (InterruptedException | ExecutionException e){
                e.printStackTrace();
            }
        });
        executor.shutdown();
    }

    /**
     * 并行求和
     */
    private int addIntegers(List<Integer> values){
        return values.parallelStream()
                .mapToInt(i->i)
                .sum();
    }

    /**
     * 使用for循环初始化数组
     */
    public static double[] imperativeInit(int size){
        double[] values = new double[size];
        for(int i=0; i<values.length; i++){
            values[i] = i;
        }
        return values;
    }

    /**
     * 使用并行化数字操作初始化数组
     */
    public static double[] parallelInit(int size){
        double[] values = new double[size];
        Arrays.parallelSetAll(values, i->i);
        return values;
    }

}
